﻿using Cofe.Core;
using Cofe.Core.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cofe.IO
{
    public static class FileFE
    {
        public static Task<IFileInfo> FromFilePathAsync(string fullParsePath,
            EntryConstructionFlags flags = EntryConstructionFlags.DefaultWithLookup)
        {
            return EntryFE.TryParsePathAsync<IFileInfo>(fullParsePath, ParsableType.ParsePath, flags);
        }

        public static async Task<IFileInfo> CopyAsync(string srcFilePath, string destFilePath)
        {
            IFileInfo srcFile = await EntryFE.TryParsePathUncachedAsync<IFileInfo>(srcFilePath);
            if (srcFile == null)
                throw new System.IO.FileNotFoundException(srcFilePath + " is not found.");

            string destPath = PathFE.GetDirectoryName(destFilePath);
            string destName = PathFE.GetFileName(destFilePath);

            IDirectoryInfo destDir = await DirectoryFE.CreateDirectoryAsync(destPath);                                    
            
            using (var inputStream = (await srcFile.OpenReadAsync()).Stream)
            using (var outputStream = (await OpenWriteAsync(destFilePath)).Stream)
                await StreamUtils.CopyStreamAsync(inputStream, outputStream, false, false, true);

            return await EntryFE.TryParsePathUncachedAsync<IFileInfo>(destFilePath);
        }

        public static async Task<IFileInfo> MoveAsync(string srcFilePath, string destFilePath)
        {
            IFileInfo srcFile = await EntryFE.TryParsePathUncachedAsync<IFileInfo>(srcFilePath);
            if (srcFile == null)
                throw new System.IO.FileNotFoundException(srcFilePath + " is not found.");

            IFileInfo destFile = await CopyAsync(srcFilePath, destFilePath);
            if (destFile == null)
                throw new System.IO.IOException("Copy failed.");

            await srcFile.DeleteAsync();

            return destFile;
        }

        public static async Task<StreamContainer> OpenReadAsync(string filePath)
        {
            IFileInfo file = await EntryFE.TryParsePathUncachedAsync<IFileInfo>(filePath);
            if (file == null)
                throw new System.IO.FileNotFoundException(filePath + " is not a file or not found.");
            return await file.OpenReadAsync();            
        }

        public static async Task<StreamContainer> OpenWriteAsync(string filePath)
        {
            IFileInfo file = await EntryFE.TryParsePathUncachedAsync<IFileInfo>(filePath);
            if (file != null)
                return await file.OpenWriteAsync();

            string parentPath = PathFE.GetDirectoryName(filePath);
            string fileName = PathFE.GetFileName(filePath);
            
            IDirectoryInfo parentDir = await DirectoryFE.CreateDirectoryAsync(parentPath);
            if (parentDir == null)
                throw new System.IO.IOException("Unable to create directory " + parentPath);

            var newFile = await parentDir.CreateFileAsync(fileName);
            return await newFile.OpenWriteAsync();            
        }

        public static async Task<StreamContainer> CreateAsync(string filePath)
        {
            string dirPath = PathFE.GetDirectoryName(filePath);
            string fileName = PathFE.GetFileName(filePath);

            var createdDirectory = await DirectoryFE.CreateDirectoryAsync(dirPath);
            var createdFile = await createdDirectory.CreateFileAsync(fileName);

            return await createdFile.OpenWriteAsync();
        }

        public static bool Exists(string filePath)
        {
            IFileInfo foundFile = (EntryFE.TryParsePathUncachedAsync<IFileInfo>(filePath)).Result;
            return foundFile != null;
        }

        public static async Task DeleteAsync(string filePath)
        {
            IFileInfo file = await EntryFE.TryParsePathUncachedAsync<IFileInfo>(filePath);
            if (file is IFileInfo)
                await file.DeleteAsync();
            else throw new System.IO.FileNotFoundException(filePath + " not found.");            
        }

    }
}
